package org.musicguardian.core.scan.local;

import java.io.File;
import java.io.FileFilter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicInteger;

import org.musicguardian.core.Core;
import org.musicguardian.core.model.Album;
import org.musicguardian.core.model.Artist;
import org.musicguardian.core.model.Library;
import org.musicguardian.core.scan.Scanner;

import entagged.audioformats.AudioFile;
import entagged.audioformats.AudioFileIO;
import entagged.audioformats.Tag;
import entagged.audioformats.exceptions.CannotReadException;

public class DirectoryScanner extends Scanner<Library> {

    private final class DirectoryFilter implements FileFilter {
	public boolean accept(File pathname) {
	    if (pathname.isDirectory()) {
		return true;
	    }
	    return false;
	}
    }

    private final class NotDirectoryFilter implements FileFilter {
	public boolean accept(File pathname) {
	    if (pathname.isDirectory()) {
		return false;
	    }
	    return true;
	}
    }

    private File directory;

    public DirectoryScanner(File directory) throws Exception {
	super();
	if (!directory.isDirectory()) {
	    throw new Exception(directory.getName() + " is not a directory");
	}
	this.directory = directory;
    }

    @Override
    public Library run() throws Exception {
	Library library = new Library(directory.getPath());
	scanDirectory(directory, library);
	return library;
    }

    @Override
    public int getTotalWork() {
	AtomicInteger filesNumber = new AtomicInteger(0);
	countFilesInDirectory(directory, filesNumber);
	return filesNumber.get();
    }

    private void countFilesInDirectory(File directory, AtomicInteger filesNumber) {
	File[] subDirectories = directory.listFiles(new DirectoryFilter());
	for (int i = 0; i < subDirectories.length; i++) {
	    countFilesInDirectory(subDirectories[i], filesNumber);
	}

	File[] subFiles = directory.listFiles(new NotDirectoryFilter());
	filesNumber.set(filesNumber.get() + subFiles.length);
    }

    private void scanDirectory(File directory, Library library) {
	File[] subDirectories = directory.listFiles(new DirectoryFilter());
	for (int i = 0; i < subDirectories.length; i++) {
	    scanDirectory(subDirectories[i], library);
	}

	File[] subFiles = directory.listFiles(new NotDirectoryFilter());
	for (int i = 0; i < subFiles.length; i++) {
	    scanFile(subFiles[i], library);
	}
    }

    private void scanFile(File fileToScan, Library library) {
	try {
	    notifyScannerListeners(fileToScan.getPath());
	    AudioFile audioFile = AudioFileIO.read(fileToScan);
	    Tag tag = audioFile.getTag();
	    if (!tag.isEmpty()) {
		Artist addAlbum = new Artist(tag.getFirstArtist())
			.addAlbum(new Album(tag.getFirstAlbum()));
		library.addArtist(addAlbum);
	    } else {
		System.err.println("Error reading file " + fileToScan.getPath()
			+ " : empty tag");
	    }
	} catch (CannotReadException e) {
	    System.err.println("Error reading file " + fileToScan.getPath()
		    + " : " + e.getMessage());
	}
    }
}
